-
-
Notifications
You must be signed in to change notification settings - Fork 134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[fix] File upload #850
[fix] File upload #850
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. |
i would guess the right thing to do is probably move to busboy, etc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch and this looks great. Thanks for working on it.
packages/waku/src/lib/utils/form.ts
Outdated
@@ -1,8 +1,16 @@ | |||
// TODO is this correct? better to use a library? | |||
export const parseFormData = (body: string, contentType: string) => { | |||
export const parseFormData = (body: ArrayBuffer, contentType: string) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you be able to create a test for this function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will try, going on vacation soon so have a lot of other projects to wrap up
i've only minorly tested the code itself, but it appears to be working in the project i found the bug in
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking forward to it. take your time.
@@ -194,13 +194,14 @@ export async function renderRsc( | |||
|
|||
let decodedBody: unknown | undefined = args.decodedBody; | |||
if (body) { | |||
const bodyStr = await streamToString(body); | |||
const bodyBuf = await streamToArrayBuffer(body); | |||
const bodyStr = arrayBufferToString(bodyBuf); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can delay calling this in the else-if block. We just need to check if the buffer has a length.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great, latest version should have this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, thanks.
We used to use busboy as React lib uses it, but it's Node.js specific and Waku now supports non-Node.js envs. |
tests are a good starting point, but really need more. large files, etc.. the current code does not pass. the tests themselves need some review for accuracy as well |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, those tests are good start. Thanks for working on it. It's hard to tell the accuracy, but it's noticeable.
2nd review 👇 . Maybe we need a test for arrayBufferToString
.
@@ -31,6 +56,13 @@ export const streamToString = async ( | |||
return outs.join(''); | |||
}; | |||
|
|||
export function arrayBufferToString(buffer: ArrayBuffer): string { | |||
const uint8Array = new Uint8Array(buffer); | |||
return Array.from(uint8Array) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not familiar but does it create a new array?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
array.from does yes, I think we should try to avoid conversions if possible, or convert once and handle from there. this feels like a hack to me
export function arrayBufferToString(buffer: ArrayBuffer): string { | ||
const uint8Array = new Uint8Array(buffer); | ||
return Array.from(uint8Array) | ||
.map((byte) => String.fromCharCode(byte)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to work for non-ASCII chars. Don't we need to use TextDecoder?
Do we have the same issue in parseFormData
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep I believe so
So I initially wrote this code as a hack to solve a specific issue for my project. I think after writing the tests and seeing some of the review comments, it might be nice to review this body of code in total and maybe write a better implementation to handle more cases (like binary, base64, quoted strings, etc). Mentioned in discord but I see Hono is doing this. Not sure if applicable given support for non node.js based runtimes, I'm not super familiar with the API's down to that level. But since Hono supports different runtimes, I imagine there are either polyfills or something to get the parsing working.
if I get a chance today I may try something as simple as this. (however I am using bun runtime so it probably has support for the node.js apis) Edit: I couldn't help myself from trying. It looks to have worked, but still failing some tests (could be poorly written tests? as this is a canonical implementation??). If this is a valid way to go it is by far the simplest and probably most robust. I am going to submit the code I have shortly, as well as updated arrayBufferToString from Hono as well |
@@ -56,13 +56,6 @@ export const streamToString = async ( | |||
return outs.join(''); | |||
}; | |||
|
|||
export function arrayBufferToString(buffer: ArrayBuffer): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hono provides this now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good. Thanks for working on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is so great! Thanks for your contribution!
I have a simple HTML form which submits a file to a server action via multipart form upload. From the client side, the file looks proper, but when the server action receives it, the file is much larger? Is there some intermediate processing of this file or improper handling in the library?
client sent:
server received:
I went through the code, and the bug largely was parsing the body as a string. Instead we have an array buffer so we can manipulate it more directly. It's possible it may still work as a string, but I believe the array buffer leaves more flexibility.
I've only tested directly in the application I've been building